﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using AmazonGlacierGUI.Core;
using AmazonGlacierGUI.Core.Helpers;
using AmazonGlacierGUI.Core.Model;
using AmazonGlacierGUI.UI.Infrastructure;
using AmazonGlacierGUI.UI.Infrastructure.MVVMFramework;
using GalaSoft.MvvmLight.Command;
using System.Timers;

namespace AmazonGlacierGUI.UI.ViewModels
{
    //25-Aug-2012 Priyan R
    public class JobsViewModel : AppViewModelBase
    {
        public const int MaxmimumSimulataniousJobs = 5;
        private Timer _timer = new Timer();

        public JobsViewModel()
        {
            Jobs = new ObservableCollection<JobViewModel>();
            WireCommands();
            LoadJobs();
            ProcessJobs();
            _timer.Interval = 500;
            _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
        }

        public override void OnInit()
        {
            if (AppContext.Current.Settings == null)
            {
                UIHelper.ShowSettingsScreen();
                if (AppContext.Current.Settings == null)
                {
                    Close();
                }
            }
            _timer.Enabled = true;
        }

        private void OnUploadCommand()
        {
            UIHelper.ShowOpenFileDialog("All files|*.*", true, (files) =>
            {
                UIHelper.ShowUploadScreen(files);
            }, () => { });
        }

        private void OnDownloadCommand()
        {
            var sourceVM = UIHelper.ShowArchiveSelectSource();
            if (!sourceVM.IsSelected) return;
            if (sourceVM.Source == ArchiveSelectSourceViewModel.SourceTypeEnum.History)
            {
                UIHelper.ShowDownloadFromHistory();
            }
            else if (sourceVM.Source == ArchiveSelectSourceViewModel.SourceTypeEnum.ArchiveId)
            {
                UIHelper.ShowDownloadArchiveByArchiveId();
            }
            else if (sourceVM.Source == ArchiveSelectSourceViewModel.SourceTypeEnum.Inventory)
            {
                UIHelper.ShowDownloadArchiveFromAmazonInventory();
            }
        }

        private void OnRemoveCommand()
        {
            UIHelper.ShowConfirm("Are you sure you want to remove the selected jobs",
                                 (v) =>
                                 {
                                     if (!v) return;
                                     Jobs.Where(p => p.CanRemove && p.IsSelected).ToList().ForEach(
                                         p => p.RemoveCommand.Execute(null));
                                 });
        }

        private void OnRestartCommand()
        {
            UIHelper.ShowConfirm("Are you sure you want to restart the selected jobs",
                                 (v) =>
                                 {
                                     if (!v) return;
                                     Jobs.Where(p => p.CanRestart && p.IsSelected).ToList().ForEach(
                                         p => p.RestartCommand.Execute(null));
                                 });
        }

        private void OnResumeCommand()
        {
            Jobs.Where(p => p.CanResume && p.IsSelected).ToList().ForEach(p => p.ResumeCommand.Execute(null));
        }

        private void OnPauseCommand()
        {
            Jobs.Where(p => p.CanPause && p.IsSelected).ToList().ForEach(p => p.PauseCommand.Execute(null));
        }
        private void OnShowDetailsCommand()
        {
            var vm = new JobDetailsViewModel(Jobs.Where(p => p.IsSelected).FirstOrDefault());
            UIHelper.ShowJobDetails(vm);
        }

        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            ExecuteOnUI(() =>
            {
                var count = Jobs.Where(p => p.IsSelected).Count();
                CanPause = count > 0 &&
                           Jobs.Where(p => p.IsSelected && p.CanPause).Count() ==
                           count;
                CanResume = count > 0 &&
                            Jobs.Where(p => p.IsSelected && p.CanResume).Count() ==
                            count;
                CanRestart = count > 0 &&
                             Jobs.Where(p => p.IsSelected && p.CanRestart).Count
                                 () == count;
                CanRemove = count > 0 &&
                            Jobs.Where(p => p.IsSelected && p.CanRemove).Count() ==
                            count;
                CanShowDetails = count == 1;
                ProcessJobs();
            });
        }

        public void AddJob(JobViewModel vm)
        {
            WireJobEvents(vm);
            vm.Initilize();
            Jobs.Add(vm);
            ProcessJobs();
        }

        private void LoadJobs()
        {
            var jobs = AppContext.Current.GetServiceFactory().AppService.GetJobs();
            Jobs = new ObservableCollection<JobViewModel>();
            foreach (var job in jobs)
            {
                var vm = new JobViewModel();
                WireJobEvents(vm);
                vm.Load(job);
                Jobs.Add(vm);
            }
        }

        public void ProcessJobs()
        {
            ProcessJobs(JobTypeEnum.Upload);
            ProcessJobs(JobTypeEnum.Download);
        }

        private bool _processing;

        private void ProcessJobs(JobTypeEnum jobType)
        {
            if (_processing) return;
            _processing = true;
            try
            {
                var jobsInQueue = Jobs.Where(p => p.JobType == jobType && p.IsQueued).ToList();
                var jobsInProgress =
                    Jobs.Where(p => p.JobType == jobType && p.JobStatus == JobStatusEnum.InProgress).ToList();
                if (jobsInQueue.Count > 0 && jobsInProgress.Count < MaxmimumSimulataniousJobs)
                {
                    var numOfJobsToStart = MaxmimumSimulataniousJobs - jobsInProgress.Count;
                    jobsInQueue.Take(numOfJobsToStart).Take(numOfJobsToStart).ToList().ForEach(j => j.Run());
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                _processing = false;
            }
        }

        private void WireJobEvents(JobViewModel job)
        {
            job.OnQueued += new EventHandler(job_OnQueued);
            job.OnRemovRequest += new EventHandler(job_OnRemovRequest);
        }

        private void WireCommands()
        {
            SettingsCommand = new RelayCommand(() => UIHelper.ShowSettingsScreen());
            DownloadCommand = new RelayCommand(OnDownloadCommand);
            UploadCommand = new RelayCommand(OnUploadCommand);
            PauseCommand = new RelayCommand(OnPauseCommand, () => CanPause);
            ResumeCommand = new RelayCommand(OnResumeCommand, () => CanResume);
            RestartCommand = new RelayCommand(OnRestartCommand, () => CanRestart);
            RemoveCommand = new RelayCommand(OnRemoveCommand, () => CanRemove);
            ShowDetailsCommand = new RelayCommand(OnShowDetailsCommand, () => CanShowDetails);
        }

   
        private void job_OnRemovRequest(object sender, EventArgs e)
        {
            var vm = (JobViewModel) sender;
            Jobs.Remove(vm);
            AppContext.Current.GetServiceFactory().AppService.RemoveJob(vm.Id);
        }

        private void job_OnQueued(object sender, EventArgs e)
        {
            ProcessJobs();
        }


        private bool _canResume;

        public bool CanResume
        {
            get { return _canResume; }
            set
            {
                if (_canResume != value)
                {
                    _canResume = value;
                    RaisePropertyChanged(() => CanResume);
                    ResumeCommand.RaiseCanExecuteChanged();
                }
            }
        }

        private bool _canRestart;

        public bool CanRestart
        {
            get { return _canRestart; }
            set
            {
                if (_canRestart != value)
                {
                    _canRestart = value;
                    RaisePropertyChanged(() => CanRestart);
                    RestartCommand.RaiseCanExecuteChanged();
                }
            }
        }

        private bool _canPause;

        public bool CanPause
        {
            get { return _canPause; }
            set
            {
                if (_canPause != value)
                {
                    _canPause = value;
                    RaisePropertyChanged(() => CanPause);
                    PauseCommand.RaiseCanExecuteChanged();
                }
            }
        }
        private bool _canShowDetails;
        public bool CanShowDetails
        {
            get { return _canShowDetails; }
            set
            {
                if (_canShowDetails != value)
                {
                    _canShowDetails = value;
                    RaisePropertyChanged(() => CanShowDetails);
                    ShowDetailsCommand.RaiseCanExecuteChanged();
                }
            }
        }

        private bool _canRemove;

        public bool CanRemove
        {
            get { return _canRemove; }
            set
            {
                if (_canRemove != value)
                {
                    _canRemove = value;
                    RaisePropertyChanged(() => CanRemove);
                    RemoveCommand.RaiseCanExecuteChanged();
                }
            }
        }

        private ObservableCollection<JobViewModel> _jobs;

        public ObservableCollection<JobViewModel> Jobs
        {
            get { return _jobs; }
            set
            {
                if (_jobs != value)
                {
                    _jobs = value;
                    RaisePropertyChanged(() => Jobs);
                }
            }
        }

        private bool _isWorking;
        private int _tryCount = 0;

        public bool IsWorking
        {
            get { return _isWorking; }
            set
            {
                if (_isWorking != value)
                {
                    _isWorking = value;
                    RaisePropertyChanged(() => IsWorking);
                }
            }
        }


        public RelayCommand UploadCommand { get; set; }
        public RelayCommand DownloadCommand { get; set; }
        public RelayCommand SettingsCommand { get; set; }
        public RelayCommand PauseCommand { get; private set; }
        public RelayCommand ResumeCommand { get; private set; }
        public RelayCommand RestartCommand { get; private set; }
        public RelayCommand RemoveCommand { get; private set; }
        public RelayCommand ShowDetailsCommand { get; private set; }

    }
}